home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 037a / exec33.zip / CHECKPAT.ASM < prev    next >
Assembly Source File  |  1991-11-21  |  20KB  |  1,044 lines

  1. ;
  2. ;    --- Version 3.3 91-11-21 16:11 ---
  3. ;
  4. ;    CHECKPAT.ASM - Utility function to check a given file/path,
  5. ;            and to resolve an incomplete path.
  6. ;            (Does not use any undocumented DOS functions.)
  7. ;
  8. ;    Public Domain Software written by
  9. ;        Thomas Wagner
  10. ;        Ferrari electronic GmbH
  11. ;        Beusselstrasse 27
  12. ;        D-1000 Berlin 21
  13. ;        Germany
  14. ;
  15. ;>e
  16. ; Assemble with
  17. ;
  18. ; tasm  /DPASCAL checkpat,checkpap           - Turbo Pascal (Tasm only), near
  19. ; tasm  /DPASCAL /DFARCALL checkpat,checkpap - Turbo Pascal (Tasm only), far
  20. ; ?asm  checkpat;                   - C, default model (small)
  21. ; ?asm  /DMODL=large checkpat               - C, large model
  22. ;
  23. ;    NOTE:    For C, change the 'model' directive below according to your
  24. ;        memory model, or define MODL=xxx on the command line.
  25. ;
  26. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  27. ;        command line, or define it here.
  28. ;
  29. ;
  30. ;   This routine accepts a file name and/or path, checks and resolves the
  31. ;   path, and splits the name into its components.
  32. ;
  33. ;   A relative path, or no path at all, is resolved to a full path
  34. ;   specification. An invalid disk drive will not cause the routine 
  35. ;   to fail.
  36. ;
  37. ;   PASCAL:
  38. ;    function checkpath (name    : string,
  39. ;                inflags : integer,
  40. ;                        drive   : string,
  41. ;                        dir     : string,
  42. ;                        fname   : string,
  43. ;                        ext     : string,
  44. ;                        fullpath: string)
  45. ;                : integer;
  46. ;   C:
  47. ;    int checkpath (char *name,     
  48. ;               int  inflags,
  49. ;                   char *drive,      
  50. ;                   char *dir,        
  51. ;                   char *fname,      
  52. ;                   char *ext,        
  53. ;                   char *fullpath);  
  54. ;
  55. ;   Parameters:
  56. ;
  57. ;    name     - Input:  file name and/or path string
  58. ;    inflags  - Input:  parameters for analysis
  59. ;               INF_NODIR: do no interpret name as directory
  60. ;    drive     - Output: drive letter, with trailing colon
  61. ;    dir     - Output: directory, with leading and trailing bakslash
  62. ;    fname     - Output: file name
  63. ;    ext     - Output: file extension, with leading dot
  64. ;    fullpath - Output: combined path
  65. ;
  66. ;    NOTE:    The input 'name' and the output 'fullpath' parameters may
  67. ;        both point to the same string. The 'fullpath' pointer will
  68. ;        only be used after completion of input parsing.
  69. ;
  70. ;    NOTE:    For Pascal, reserve one character in addition to the
  71. ;        standard maximum length for all strings, including the
  72. ;        input parameter. All strings will be zero-terminated
  73. ;        during internal processing. DO NOT pass a constant as
  74. ;        input parameter string.
  75. ;
  76. ;   Returns:
  77. ;
  78. ;    A negative value on error:
  79. ;
  80. ;        ERR_DRIVE       -1    Invalid drive
  81. ;        ERR_PATH        -2    Invalid path
  82. ;        ERR_FNAME       -3    Malformed filename
  83. ;        ERR_DRIVECHAR   -4    Illegal drive letter
  84. ;        ERR_PATHLEN     -5    Path too long
  85. ;        ERR_CRITICAL    -6    Critical error (invalid drive, drive not ready)
  86. ;
  87. ;    On error, all output strings except the drive string will be empty.
  88. ;
  89. ;    If no error occured, a positive value consisting of the bitwise OR 
  90. ;    of the following flags:
  91. ;
  92. ;        HAS_WILD        1     Filename/ext has wildcard characters
  93. ;        HAS_EXT         2     Extension specified
  94. ;        HAS_FNAME       4     Filename specified
  95. ;        HAS_PATH        8     Path specified
  96. ;        HAS_DRIVE       0x10  Drive specified
  97. ;
  98. ;            Those flags are set only if the corresponding 
  99. ;            component was given in the input string. The 
  100. ;            'drive' and 'dir' strings will always contain 
  101. ;            the resolved drive and path.
  102. ;
  103. ;        FILE_EXISTS     0x20  File exists, upper byte has attributes
  104. ;        IS_DIR        0x1000  Directory, upper byte has attributes
  105. ;
  106. ;        The file attributes returned if FILE_EXISTS or IS_DIR 
  107. ;        is set are
  108. ;            0x0100 - Read only
  109. ;            0x0200 - Hidden
  110. ;            0x0400 - System
  111. ;            0x2000 - Archive
  112. ;            0x4000 - Device
  113. ;
  114. ;<
  115. ;>d
  116. ; Assemblierung mit
  117. ;
  118. ; tasm  /DPASCAL checkpat,checkpatp          - Turbo Pascal (nur Tasm), near
  119. ; tasm  /DPASCAL /DFARCALL checkpat,checkpatp - Turbo Pascal (nur Tasm), far
  120. ; ?asm  checkpat;                    - C, default model (small)
  121. ; ?asm  /DMODL=large checkpat                - C, large model
  122. ;
  123. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  124. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  125. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  126. ;
  127. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  128. ;        angeben, oder das Symbol in dieser Quelle definieren.
  129. ;
  130. ;   Diese Routine erwartet einen Dateinamen und/oder Pfad, prüft ihn
  131. ;   und löst den Pfad auf, und teilt den Namen in seine Komponenten.
  132. ;
  133. ;   Ein relativer Pfad, oder eine fehlende Pfadangabe, wird in eine
  134. ;   absolute Pfadangabe konvertiert. Ein ungültiger Laufwerksbuchstabe
  135. ;   führt nicht zum Abbruch.
  136. ;
  137. ;   PASCAL:
  138. ;    function checkpath (name    : string,
  139. ;                inflags : integer,
  140. ;                        drive   : string,
  141. ;                        dir     : string,
  142. ;                        fname   : string,
  143. ;                        ext     : string,
  144. ;                        fullpath: string)
  145. ;                : integer;
  146. ;   C:
  147. ;    int checkpath (char *name,     
  148. ;               int  inflags,
  149. ;                   char *drive,      
  150. ;                   char *dir,        
  151. ;                   char *fname,      
  152. ;                   char *ext,        
  153. ;                   char *fullpath);  
  154. ;
  155. ;   Parameter:
  156. ;
  157. ;    name     - Input:  Filename und/oder Pfad
  158. ;    inflags  - Input:  Analyse-Parameter
  159. ;               INF_NODIR: Name nicht als Directory interpretieren
  160. ;    drive     - Output: Laufwerksbuchstabe, mit abschließendem Doppelpunkt
  161. ;    dir     - Output: Directory, mit führendem und abschließendem '\'
  162. ;    fname     - Output: Filename
  163. ;    ext     - Output: File extension, mit führendem Punkt
  164. ;    fullpath - Output: Kombinierter Pfad
  165. ;
  166. ;   Liefert:
  167. ;
  168. ;    Einen negativen Wert bei Fehler:
  169. ;
  170. ;        ERR_DRIVE       -1    Ungültiges Laufwerk
  171. ;        ERR_PATH        -2    Ungültiger Pfad
  172. ;        ERR_FNAME       -3    Fehlerhafter Dateiname
  173. ;        ERR_DRIVECHAR   -4    Illegaler Laufwerksbuchstabe
  174. ;        ERR_PATHLEN     -5    Pfad zu lang
  175. ;        ERR_CRITICAL    -6    Critical error (Illegales Laufwerk,
  176. ;                      Laufwerk nicht bereit)
  177. ;
  178. ;    Bei Fehler sind alle Ausgabestrings außer 'drive' leer.
  179. ;
  180. ;    Wenn kein Fehler auftrat einen positiven Wert der aus dem
  181. ;    bitweisen OR der folgenden Flags besteht:
  182. ;
  183. ;        HAS_WILD        1     Filename/ext enthält Wildcard-Zeichen
  184. ;        HAS_EXT         2     Extension angegeben
  185. ;        HAS_FNAME       4     Filename angegeben
  186. ;        HAS_PATH        8     Pfad angegeben
  187. ;        HAS_DRIVE       0x10  Laufwerk angegeben
  188. ;
  189. ;            Diese Flags sind nur gesetzt wenn die entsprechende 
  190. ;            Komponente im Eingabestring enthalten war. Die 
  191. ;            'drive' und 'dir' Ausgabestrings enthalten stets 
  192. ;            den aufgelösten Laufwerks- und Pfadstring.
  193. ;
  194. ;        FILE_EXISTS     0x20  Datei existiert, Attribute im oberen Byte
  195. ;        IS_DIR        0x1000  Directory, Attribute im oberen Byte
  196. ;
  197. ;        Die Dateiattribute die geliefert werden wenn FILE_EXISTS 
  198. ;        oder IS_DIR gesetzt ist sind:
  199. ;
  200. ;            0x0100 - Read only
  201. ;            0x0200 - Hidden
  202. ;            0x0400 - System
  203. ;            0x2000 - Archive
  204. ;            0x4000 - Device
  205. ;
  206. ;<
  207. ;
  208.     IFDEF    PASCAL
  209.     .model    tpascal
  210.     IFDEF    FARCALL
  211.     %out    Pascal, far calls
  212.     ELSE
  213.     %out    Pascal, near calls
  214.     ENDIF
  215. ptrsize    =    1
  216.     ELSE
  217.     IFNDEF    MODL
  218.     .model    small,c
  219.     %out    small model
  220.     ELSE
  221. %    .model    MODL,c
  222. %    %out    MODL model
  223.     ENDIF
  224. ptrsize    =    @DataSize
  225.     ENDIF
  226. ;
  227. ldds    macro    reg,var
  228.     IF    ptrsize
  229.     lds    reg,var
  230.     ELSE
  231.     mov    reg,var
  232.     ENDIF
  233.     endm
  234. ;
  235. lddsf    macro    reg,var
  236.     IF    ptrsize
  237.     lds    reg,var
  238.     ELSE
  239.     mov    ds,dseg
  240.     mov    reg,var
  241.     ENDIF
  242.     endm
  243. ;
  244. ldes    macro    reg,var
  245.     IF    ptrsize
  246.     les    reg,var
  247.     ELSE
  248.     mov    reg,var
  249.     ENDIF
  250.     endm
  251. ;
  252. ldesf    macro    reg,var
  253.     IF    ptrsize
  254.     les    reg,var
  255.     ELSE
  256.     mov    es,dseg
  257.     mov    reg,var
  258.     ENDIF
  259.     endm
  260. ;
  261.     public    checkpath
  262.     public    exists
  263. ;
  264. ERR_DRIVE    =    -1
  265. ERR_PATH    =    -2
  266. ERR_FNAME    =    -3
  267. ERR_DRIVECHAR    =    -4
  268. ERR_PATHLEN    =    -5
  269. ERR_CRITICAL    =    -6
  270. ;
  271. HAS_WILD    =    1
  272. HAS_EXT        =    2
  273. HAS_FNAME    =    4
  274. HAS_PATH    =    8
  275. HAS_DRIVE    =    10h
  276. FILE_EXISTS    =    20h
  277. IS_DIR        =    1000h
  278. ;
  279. MAXPATH        =    66
  280. ;
  281. INF_NODIR    =    1
  282. ;
  283.     IFDEF    PASCAL
  284.     .data
  285.     ELSE
  286.     IFDEF    TC_HUGE
  287.     .fardata?    checkpat_data
  288.     ELSE
  289.     .data?
  290.     ENDIF
  291.     ENDIF
  292. ;
  293. save24        label    dword
  294. sav24_off    dw    ?
  295. sav24_seg    dw    ?
  296. fail        dw    ?
  297. dfltpath    db    68 dup(?)
  298. ;
  299.     .code
  300. ;
  301. @strcpy    proc    near
  302.     lodsb
  303.     stosb
  304.     or    al,al
  305.     jnz    @strcpy
  306.     dec    di
  307.     ret
  308. @strcpy    endp
  309. ;
  310.     IFDEF    PASCAL
  311. @strlen    proc    near
  312.     push    di
  313.     inc    di
  314.     xor    ax,ax
  315.     mov    cx,-1
  316.     repne scasb
  317.     not    cx
  318.     dec    cx
  319.     pop    di
  320.     mov    es:[di],cl
  321.     ret
  322. @strlen    endp
  323.     ENDIF
  324. ;
  325. @int24_handler    proc far
  326.     push    ds
  327.     IFDEF    TC_HUGE
  328.     mov    ax,SEG checkpat_data
  329.     ELSE
  330.     IFDEF    PASCAL
  331.     mov    ax,SEG fail
  332.     ELSE
  333.     mov    ax,SEG DGROUP
  334.     ENDIF
  335.     ENDIF
  336.     mov    ds,ax
  337.     mov    fail,1
  338.     pop    ds
  339.     xor    ax,ax        ; ignore (for compatibility with DOS < 3.1)
  340.     iret
  341. @int24_handler    endp
  342. ;
  343. ;
  344.     IFDEF    PASCAL
  345.     IFDEF    FARCALL
  346. checkpath PROC far uses ds, string: dword, inflags: word, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  347.     ELSE
  348. checkpath PROC near uses ds, string: dword, inflags: word, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  349.     ENDIF
  350.     ELSE
  351. checkpath PROC uses ds si di, string: ptr byte, inflags: word, drive: ptr byte, path: ptr byte, fname: ptr byte, ext: ptr byte, fullpath: ptr byte
  352.     ENDIF
  353.     local    drv: word,flags:word,dseg: word
  354. ;
  355.     IFDEF    TC_HUGE
  356.     mov    ax,SEG my_data
  357.     mov    ds,ax
  358.     ENDIF
  359.     mov    dseg,ds
  360.     IFDEF    PASCAL
  361.     cld
  362.     ENDIF
  363. ;
  364. ;    save old critical error handler, install own
  365. ;
  366.     mov    ax,3524h
  367.     int    21h
  368.     mov    sav24_off,bx
  369.     mov    sav24_seg,es
  370.     mov    fail,0
  371.     mov    ax,cs
  372.     mov    ds,ax
  373.     mov    dx,offset @int24_handler
  374.     mov    ax,2524h
  375.     int    21h
  376.     mov    ds,dseg
  377. ;
  378. ;    Init output strings & flags
  379. ;
  380.     xor    ax,ax
  381.     mov    flags,ax
  382.     ldesf    di,path
  383.     IFDEF    PASCAL
  384.     stosw
  385.     ELSE
  386.     stosb
  387.     ENDIF
  388.     ldes    di,fname
  389.     IFDEF    PASCAL
  390.     stosw
  391.     ELSE
  392.     stosb
  393.     ENDIF
  394.     ldes    di,ext
  395.     IFDEF    PASCAL
  396.     stosw
  397.     ELSE
  398.     stosb
  399.     ENDIF
  400. ;
  401. ;------ Check the drive. If none was given, use current drive.
  402. ;
  403.     ldes    di,drive
  404.     IFDEF    PASCAL
  405.     inc    di
  406.     ENDIF
  407.     ldds    si,string
  408.     IFDEF    PASCAL
  409. ; for pascal, zero-terminate input string
  410.     lodsb
  411.     mov    bl,al
  412.     xor    ah,ah
  413.     mov    [si+bx],ah
  414.     ENDIF
  415. ;
  416. ; skip leading whitespace
  417. ;
  418. skip_space:
  419.     lodsb
  420.     cmp    al,' '
  421.     je    skip_space
  422.     cmp    al,09h
  423.     je    skip_space
  424.     dec    si
  425. ;
  426.     or    al,al
  427.     jz    no_drive
  428.     cmp    byte ptr 1[si],':'
  429.     je    drive_there
  430. ;
  431. no_drive:
  432.     mov    ah,19h            ; get default drive
  433.     int    21h
  434.     add    al,'A'
  435.     stosb
  436.     mov    bl,al
  437.     mov    al,':'
  438.     stosb
  439.     jmp    short check_drive
  440. ;
  441. badchar:
  442.     mov    ax,ERR_DRIVECHAR
  443.     jmp    error_exit
  444. ;
  445. drive_there:
  446.     inc    si
  447.     and    al,NOT 20h        ; convert to uppercase
  448.     cmp    al,'A'
  449.     jb    badchar
  450.     cmp    al,'A'+1fh        ; Novell allows some strange chars
  451.     ja    badchar
  452.     stosb
  453.     or    flags,HAS_DRIVE
  454.     mov    bl,al
  455.     movsb
  456. ;
  457. ;    Now check the drive for validity by getting the current directory
  458. ;    of this drive (we need it anyway later on)
  459. ;
  460. check_drive:
  461.     and    bx,1fh
  462.     mov    drv,bx
  463.     xor    al,al
  464.     stosb
  465. ;
  466.     push    ds
  467.     push    si
  468. ;
  469.     mov    ax,dseg
  470.     mov    ds,ax
  471.     mov    es,ax
  472.     mov    si,offset dfltpath+3
  473.     mov    ah,47h        ; get current directory
  474.     mov    dx,drv        ; drive number
  475.     int    21h
  476.     jc    cpath_bad
  477.     cmp    fail,0
  478.     je    cpath_good
  479. ;
  480. ;    Get dir returned an error -> the drive is invalid.
  481. ;
  482. cpath_bad:
  483.     add    sp,4
  484.     mov    ax,ERR_DRIVE
  485.     jmp    error_exit    ; can't continue with invalid drive
  486. ;
  487. ;    The drive is valid, edit the current path to include
  488. ;    leading drive letter, colon, and backslash.
  489. ;    Also, copy the path into the path output string, in case no
  490. ;    path is given in the input, and append trailing backslash to it.
  491. ;
  492. cpath_good:
  493.     mov    di,offset dfltpath
  494.     mov    ax,drv
  495.     add    al,'A'-1
  496.     stosb
  497.     mov    al,':'
  498.     stosb
  499.     mov    si,di        ; point to start of path
  500.     mov    al,'\'
  501.     stosb
  502.     ldes    di,path
  503.     IFDEF    PASCAL
  504.     inc    di
  505.     ENDIF
  506.     call    @strcpy
  507.     mov    al,'\'
  508.     cmp    byte ptr es:[di-1],al    ; root dir?
  509.     je    drive_ok        ; then no second backslash
  510.     stosb                ; else append backslash
  511. ;
  512. ;
  513. ;------ Drive checked, is valid. Now separate path and filename.
  514. ;
  515. drive_ok:
  516.     pop    si
  517.     pop    ds
  518.     push    si
  519.     push    di
  520.     push    es
  521.     mov    di,si
  522.     mov    ax,ds
  523.     mov    es,ax
  524. ;
  525. ;    find the end of the string
  526. ;
  527.     xor    ax,ax
  528.     mov    cx,-1
  529.     repne scasb
  530.     mov    si,di
  531.     pop    es
  532.     pop    di
  533.     not    cx
  534.     dec    cx
  535.     jnz    has_fnp        ; continue if there's more in the string
  536.     add    sp,2
  537.     stosb            ; terminate path string
  538.     jmp    check_fname    ; exit if no path or filename
  539. ;
  540. ;    search from the end for slash/backslash
  541. ;
  542. has_fnp:
  543.     sub    si,2        ; last char of string
  544.     mov    bx,5c2fh    ; the two slashes
  545.     std            ; backwards scan
  546. ;
  547. spath:
  548.     lodsb
  549.     cmp    al,bl
  550.     je    pfound
  551.     cmp    al,bh
  552.     je    pfound
  553.     loop    spath
  554. ;
  555. ;    no slash/backslash -> no path given
  556. ;
  557.     cld
  558.     pop    si
  559.     xor    cx,cx
  560.     jmp    short cfname
  561. ;
  562. longpath:
  563.     mov    ax,ERR_PATHLEN
  564.     jmp    error_exit
  565. ;
  566. ;    copy the path (note: CX has length of path including slash)
  567. ;
  568. pfound:
  569.     cld
  570.     pop    si
  571.     cmp    cx,MAXPATH
  572.     ja    longpath
  573.     or    flags,HAS_PATH        ; we have a path
  574.     ldes    di,path
  575.     IFDEF    PASCAL
  576.     inc    di
  577.     ENDIF
  578.     push    cx
  579.     rep movsb
  580.     pop    cx
  581. ;
  582. ;    check for special filenames '.' and '..', and add them to
  583. ;    the path if present.
  584. ;    The special form that adds a '.' for every level further down
  585. ;    the tree is recognized, and translated into the DOS-form '..\'
  586. ;
  587. cfname:
  588.     cmp    byte ptr [si],'.'
  589.     jne    path_finished
  590.     cmp    byte ptr [si+1],'.'
  591.     je    is_special
  592.     cmp    byte ptr [si+1],0
  593.     jne    path_finished
  594. ;
  595. is_special:
  596.     or    flags,HAS_PATH        ; we have a path
  597.     mov    bx,MAXPATH
  598.     sub    bx,cx
  599.     mov    cx,2
  600.     lodsb
  601. ;
  602. copy_special:
  603.     or    bx,bx
  604.     jz    longpath
  605.     dec    bx
  606.     stosb
  607.     lodsb
  608.     or    al,al
  609.     jz    special_finished
  610.     cmp    al,'.'
  611.     jne    badname
  612.     loop    copy_special
  613. ;
  614. add_special:
  615.     sub    bx,3
  616.     jle    longpath
  617.     mov    al,'\'
  618.     stosb
  619.     mov    al,'.'
  620.     stosb
  621.     stosb
  622.     lodsb
  623.     or    al,al
  624.     jz    special_finished
  625.     cmp    al,'.'
  626.     jne    badname
  627.     jmp    add_special
  628. ;
  629. badname:
  630.     mov    ax,ERR_FNAME
  631.     jmp    error_exit
  632. ;
  633. special_finished:
  634.     dec    si
  635.     mov    al,'\'
  636.     stosb
  637. ;
  638. ;    now copy the filename and extension (limited to 8/3 chars)
  639. ;
  640. path_finished:
  641.     xor    al,al            ; terminate path
  642.     stosb
  643. ;
  644.     mov    bx,2a3fh        ; the two wildcards '*' and '?'
  645.     ldes    di,fname
  646.     IFDEF    PASCAL
  647.     inc    di
  648.     ENDIF
  649.     mov    cx,8            ; max 8 for name
  650. ;
  651. cfnloop:
  652.     lodsb
  653.     or    al,al            ; end of string?
  654.     jz    cfndot
  655.     cmp    al,'.'
  656.     je    cfndot
  657.     jcxz    cfnloop            ; skip if 8 chars copied
  658.     stosb
  659.     dec    cx
  660.     or    flags,HAS_FNAME
  661.     cmp    al,bl            ; check for wildcards    
  662.     je    fnwild
  663.     cmp    al,bh
  664.     jne    cfnloop
  665. ;
  666. fnwild:
  667.     or    flags,HAS_WILD
  668.     jmp    cfnloop
  669. ;
  670. cfndot:
  671.     mov    ah,al            ; save terminator (0 or '.')
  672.     xor    al,al
  673.     stosb                ; terminate filename
  674.     or    ah,ah
  675.     jz    no_ext            ; jump if at end of string
  676. ;
  677. ;    extension present, copy it.
  678. ;
  679.     or    flags,HAS_EXT
  680.     ldes    di,ext
  681.     IFDEF    PASCAL
  682.     inc    di
  683.     ENDIF
  684.     mov    cx,3
  685.     mov    al,ah
  686.     stosb                ; store '.' as first ext char
  687. ;
  688. cextloop:
  689.     lodsb
  690.     or    al,al
  691.     jz    cextend
  692.     stosb
  693.     cmp    al,bl            ; check for wildcards    
  694.     je    extwild
  695.     cmp    al,bh
  696.     jne    cextcont
  697. ;
  698. extwild:
  699.     or    flags,HAS_WILD
  700. ;
  701. cextcont:
  702.     loop    cextloop
  703. ;
  704. cextend:
  705.     xor    al,al
  706.     stosb                ; terminate extension
  707. ;
  708. ;
  709. no_ext:
  710.     test    flags,HAS_PATH
  711.     jz    check_fname
  712. ;
  713. ;    A path was specified, check it:
  714. ;    Change the current directory to the one specified. 
  715. ;    If valid, read back the new directory string 
  716. ;    (which has '.' and '..' resolved).
  717. ;    In any case, restore the current directory.
  718. ;
  719.     ldes    di,fullpath    ; make path string from drive and path
  720.     IFDEF    PASCAL
  721.     inc    di
  722.     ENDIF
  723.     ldds    si,drive
  724.     IFDEF    PASCAL
  725.     inc    si
  726.     ENDIF
  727.     call    @strcpy
  728.     ldds    si,path
  729.     IFDEF    PASCAL
  730.     inc    si
  731.     ENDIF
  732.     call    @strcpy
  733.     cmp    byte ptr es:[di-2],':'    ; root dir ?
  734.     je    no_slstrip        ; then don't strip backslash
  735.     mov    byte ptr es:[di-1],0    ; else remove trailing '\'
  736. ;
  737. no_slstrip:
  738.     xor    cx,cx        ; cx is 'path ok' flag (init to not ok)
  739.     ldds    dx,fullpath
  740.     IFDEF    PASCAL
  741.     inc    dx
  742.     ENDIF
  743.     ldes    di,path
  744.     IFDEF    PASCAL
  745.     inc    di
  746.     ENDIF
  747.     mov    ah,3bh        ; change current directory
  748.     int    21h
  749.     mov    ds,dseg
  750.     jc    rest_path    ; skip dir reading if invalid
  751.     cmp    fail,0
  752.     jne    rest_path
  753. ;
  754. ;    read back path
  755. ;
  756.     ldds    si,path
  757.     IFDEF    PASCAL
  758.     inc    si
  759.     ENDIF
  760.     inc    si        ; leave space for leading '\'
  761.     mov    ah,47h        ; get current directory
  762.     mov    dx,drv        ; drive number
  763.     int    21h
  764.     mov    ds,dseg
  765.     jc    rest_path    ; shouldn't happen, but...
  766.     cmp    fail,0
  767.     jne    rest_path
  768. ;
  769.     mov    byte ptr es:[di],'\'    ; prefix with '\'
  770.     xor    ax,ax
  771.     mov    cx,-1
  772.     repne scasb            ; find end of string
  773.     not    cx
  774.     cmp    cx,2
  775.     je    rest_path        ; don't append trailing '\' if root
  776.     mov    byte ptr es:[di-1],'\'
  777.     stosb                ; terminate
  778. ;
  779. rest_path:
  780.     mov    dx,offset dfltpath
  781.     mov    ah,3bh
  782.     int    21h
  783. ;
  784. ;    was the path ok?
  785. ;
  786.     or    cx,cx
  787.     jnz    check_fname
  788. ;
  789. ;    exit if not
  790. ;
  791.     mov    ax,ERR_PATH
  792.     jmp    error_exit
  793. ;
  794. ;    the path was ok, now check the filename if it doesn't contain
  795. ;    wildcard chars.
  796. ;
  797. check_fname:
  798.     test    flags,HAS_WILD
  799.     jz    checkfn1
  800.     jmp    ready
  801. ;
  802. checkfn1:
  803.     ldesf    di,fullpath    ; make full path string
  804.     IFDEF    PASCAL
  805.     inc    di
  806.     ENDIF
  807.     lddsf    si,drive
  808.     IFDEF    PASCAL
  809.     inc    si
  810.     ENDIF
  811.     call    @strcpy
  812.     ldds    si,path
  813.     IFDEF    PASCAL
  814.     inc    si
  815.     ENDIF
  816.     call    @strcpy
  817.     test    flags,HAS_FNAME OR HAS_EXT
  818.     jnz    checkfn2
  819. ;
  820. ;    No filename, get the attribute of the directory
  821. ;
  822.     or    flags,IS_DIR
  823.     dec    di
  824.     mov    byte ptr es:[di],0    ; clear trailing '\'
  825.     dec    di
  826.     cmp    byte ptr es:[di],':'    ; root dir?
  827.     je    no_dirchk        ; then don't get attribute
  828.     ldds    dx,fullpath
  829.     IFDEF    PASCAL
  830.     inc    dx
  831.     ENDIF
  832.     mov    ax,4300h    ; get attribute
  833.     int    21h
  834.     mov    ds,dseg
  835.     jc    no_attrib    ; shouldn't happen
  836.     cmp    fail,0
  837.     jne    no_attrib
  838.     mov    ax,flags
  839.     mov    ah,cl
  840.     and    ah,7fh
  841.     mov    flags,ax
  842. no_dirchk:
  843.     jmp    ready
  844. ;
  845. no_attrib:
  846.     mov    ax,ERR_PATH
  847.     jmp    error_exit
  848. ;
  849. checkfn2:
  850.     ldds    si,fname
  851.     IFDEF    PASCAL
  852.     inc    si
  853.     ENDIF
  854.     call    @strcpy
  855.     ldds    si,ext
  856.     IFDEF    PASCAL
  857.     inc    si
  858.     ENDIF
  859.     call    @strcpy
  860. ;
  861.     mov    ah,2fh        ; get current DTA
  862.     int    21h        ; ES:BX has current DTA
  863.     push    bx
  864.     push    es
  865. ;
  866.     mov    ds,dseg
  867.     mov    dx,offset dfltpath
  868.     mov    ah,1ah        ; set DTA
  869.     int    21h
  870. ;
  871.     ldds    dx,fullpath
  872.     IFDEF    PASCAL
  873.     inc    dx
  874.     ENDIF
  875.     mov    cx,10110B    ; search all except label
  876.     mov    ah,4eh        ; search for first
  877.     int    21h
  878.     mov    ds,dseg
  879.     jc    no_file
  880.     cmp    fail,0
  881.     jne    no_file
  882. ;
  883.     mov    ax,flags
  884.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  885.     test    ah,10h        ; subdirectory?
  886.     jz    no_subdir
  887. ;
  888. ;    The filename specifies a subdirectory. Append it to the path.
  889. ;
  890.     test    inflags,INF_NODIR
  891.     jnz    no_file
  892.     ldesf    di,path
  893.     IFDEF    PASCAL
  894.     inc    di
  895.     ENDIF
  896.     mov    cx,-1
  897.     xor    ax,ax
  898.     repne scasb
  899.     dec    di
  900.     mov    si,offset dfltpath+1eh
  901.     call    @strcpy
  902.     mov    al,'\'
  903.     stosb
  904.     xor    al,al
  905.     stosb
  906.     ldes    di,fname
  907.     IFDEF    PASCAL
  908.     inc    di
  909.     ENDIF
  910.     stosb
  911.     ldes    di,ext
  912.     IFDEF    PASCAL
  913.     inc    di
  914.     ENDIF
  915.     stosb
  916.     mov    ax,flags
  917.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  918.     and    ah,7fh        ; make sure it's positive
  919.     and    al,NOT (HAS_FNAME OR HAS_EXT)
  920.     or    al,HAS_PATH
  921.     mov    flags,ax
  922.     jmp    short no_file
  923. ;
  924. no_subdir:
  925.     or    al,FILE_EXISTS
  926.     and    ah,7fh        ; make sure it's positive
  927.     mov    flags,ax
  928. ;
  929. no_file:
  930.     pop    ds
  931.     pop    dx
  932.     mov    ah,1ah
  933.     int    21h        ; restore DTA
  934. ;
  935. ready:
  936.     ldesf    di,fullpath    ; make full path string
  937.     IFDEF    PASCAL
  938.     inc    di
  939.     ENDIF
  940.     lddsf    si,drive
  941.     IFDEF    PASCAL
  942.     inc    si
  943.     ENDIF
  944.     call    @strcpy
  945.     ldds    si,path
  946.     IFDEF    PASCAL
  947.     inc    si
  948.     ENDIF
  949.     call    @strcpy
  950.     ldds    si,fname
  951.     IFDEF    PASCAL
  952.     inc    si
  953.     ENDIF
  954.     call    @strcpy
  955.     ldds    si,ext
  956.     IFDEF    PASCAL
  957.     inc    si
  958.     ENDIF
  959.     call    @strcpy
  960.     mov    ds,dseg
  961.     mov    ax,flags
  962. ;
  963. error_exit:
  964.     mov    ds,dseg
  965.     cmp    fail,0
  966.     je    nofail
  967.     mov    ax,ERR_CRITICAL
  968. ;
  969. nofail:
  970.     push    ax
  971.     cmp    ax,0
  972.     jge    no_error
  973.     ldesf    di,fullpath
  974.     mov    word ptr es:[di],0
  975. ;
  976. no_error:
  977.     lds    dx,save24
  978.     mov    ax,2524h
  979.     int    21h
  980.     IFDEF    PASCAL
  981.     ldesf    di,drive
  982.     call    @strlen
  983.     ldes    di,path
  984.     call    @strlen
  985.     ldes    di,fname
  986.     call    @strlen
  987.     ldes    di,ext
  988.     call    @strlen
  989.     ldes    di,fullpath
  990.     call    @strlen
  991.     ENDIF
  992.     pop    ax
  993. ;
  994.     ret
  995. ;
  996. checkpath endp
  997. ;
  998. ;
  999. ;e Returns TRUE if a file with name 'fname' exists.
  1000. ;d Liefert TRUE wenn eine Datei mit dem Namen 'fname' existiert.
  1001. ;
  1002.     IFDEF    PASCAL
  1003.     IFDEF    FARCALL
  1004. exists    PROC far uses ds, fname: dword
  1005.     ELSE
  1006. exists    PROC near uses ds, fname: dword
  1007.     ENDIF
  1008.     ELSE
  1009. exists    PROC    uses ds, fname: ptr byte
  1010.     ENDIF
  1011. ;
  1012.     IFDEF    TC_HUGE
  1013.     mov    ax,SEG my_data
  1014.     mov    ds,ax
  1015.     ENDIF
  1016. ;
  1017.     IFDEF    PASCAL
  1018.     ldds    si,fname
  1019. ; for pascal, zero-terminate input string
  1020.     lodsb
  1021.     mov    bl,al
  1022.     xor    bh,bh
  1023.     mov    [si+bx],bh
  1024.     mov    dx,si
  1025.     ELSE
  1026.     ldds    dx,fname
  1027.     ENDIF
  1028. ;
  1029.     mov    ax,4300h    ; get file attributes
  1030.     int    21h
  1031.     mov    ax,0
  1032.     jc    exists_end
  1033.     test    cx,10h        ; directory?
  1034.     jnz    exists_end
  1035.     inc    ax
  1036. ;
  1037. exists_end:
  1038.     ret
  1039. ;
  1040. exists    endp
  1041. ;
  1042.     end
  1043.  
  1044.